/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.fjala.softure.tree.hashTree;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.fjala.softure.tree.Node;
import org.fjala.softure.tree.Tree;

/**
 *
 * @author f3r
 */
public class HashTree<T extends Comparable> implements Tree<T> {

    /**
     * Root of the Tree
     */
    private BinaryHashNode<T> root;

    /**
     * Generates a root node from a value
     *
     * @param t Value to be added
     */
    public HashTree(T t) {
        root = new BinaryHashNode<T>(t);
    }

    /**
     * Sets a binary node
     *
     * @param r Node to be set
     */
    public HashTree(BinaryHashNode<T> r) {
        root = r;
    }

    /**
     * Sorts the Hash Tree
     *
     * @return A sorted List of Nodes
     */
    public List<Node<T>> sortHashTree() {
        List<Node<T>> list = root.getAllChildren(root);
        list.add(root);

        return bubbleSort(list);
    }

    @Override
    public void replace(T oldElement, T newElement) {
        Node<T> replaceNode = root.getMap().get(oldElement);
        ((BinaryHashNode) replaceNode).setValue(newElement);
    }

    @Override
    public Node<T> getRoot() {
        return root;
    }

    @Override
    public boolean add(Node<T> parent, T element) {
        BinaryHashNode<T> binaryNode;
        Node<T> parentNode = root.getMap().get(parent.getData().hashCode());

        if(parentNode != null) {
            binaryNode = new BinaryHashNode<T>(element);
            parentNode.addChild(binaryNode);

            return true;
        }

        return false;
    }

    @Override
    public int size() {
        return root.getMap().size();
    }

    @Override
    public boolean isEmpty() {
        return !root.hasChildren();
    }

    @Override
    public boolean contains(Object o) {
        Node<T> node = root.getMap().get(o.hashCode());
        return node != null;
    }

    @Override
    public Iterator<T> iterator() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Object[] toArray() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public <T> T[] toArray(T[] a) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean add(T e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Sort a List using bubble sort Algorithm
     *
     * @param l List to be sorted
     *
     * @return A sorted list of Nodes
     */
    private List<Node<T>> bubbleSort(List<Node<T>> l) {
        if(l.size() <= 1) {
            return l;
        }

        List<Node<T>> list = l;
        Node<T> elem1;
        Node<T> elem2;

        for(int i = 0; i < list.size() - 1; i += 1) {
            for(int j = i + 1; j < list.size(); j += 1) {
                elem1 = list.get(i);
                elem2 = list.get(j);

                if(elem1.getData().compareTo(elem2.getData()) > 0) {
                    swap(list, i, j);
                }
            }

        }

        return list;
    }

    /**
     * Swap values in a List
     *
     * @param l List to make the swap
     * @param index1 Index of the Less Value
     * @param index2 Index of the Great Value
     */
    private void swap(List<Node<T>> l, int index1, int index2) {
        Node<T> aux = l.get(index1);
        l.set(index1, l.get(index2));
        l.set(index2, aux);
    }
}
